﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.NetworkInformation;
using System.Net;
using System.Collections;
using System.ComponentModel;

/*
     This file is part of Plogger.

    Plogger is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Plogger is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Plogger.  If not, see <http://www.gnu.org/licenses/>.
  
 */

namespace PingLogger
{
    public class Pinger : IDisposable
    {
        //Public fields.
        public IPAddress Address;
        public List<string> PingResult = new List<string>();
        public int RoundTrips = 10000;
        public DateTime Time = DateTime.Now;

        //Private fields.
        private Ping PingSender;
        private List<PingReply> Reply = new List<PingReply>();
        private List<string> PingReply = new List<string>();
        private string IP;
        private string Buff;
        private string Ttl;

        //Dispose
        private bool disposed = false;
        private Component component = new Component();
        private IntPtr handle;

        public Pinger(IntPtr pointer)
        {
            this.Init(pointer);
        }

        public Pinger(IntPtr pointer, string address)
        {
            this.Init(pointer);
            if (address.Length < 5)
                address = "ping.sunet.se";

            IPAddress[] ip = Dns.GetHostAddresses(address);

            this.Address = ip.FirstOrDefault<IPAddress>();
        }

        public Pinger(IntPtr pointer, string address, string rt)
        {
            this.Init(pointer);
            int r;
            if (address.Length < 5)
                address = "ping.sunet.se";

            if (int.TryParse(rt, out r))
            {
                this.RoundTrips = r;
            }

            IPAddress[] ip = Dns.GetHostAddresses(address);

            this.Address = ip.FirstOrDefault<IPAddress>();
        }

        public Pinger(IntPtr pointer, string address, int rt)
        {
            this.Init(pointer);

            if (address.Length < 5)
                address = "ping.sunet.se";

            IPAddress[] ip = Dns.GetHostAddresses(address);

            this.Address = ip.FirstOrDefault<IPAddress>();

            this.RoundTrips = rt;
        }

        public void StartPing()
        {
            for (int i = 0; i < this.RoundTrips; i++)
                this.Reply.Add(PingSender.Send(this.Address));

            this.PingSender.Dispose();
            this.ProcessPings();
        }

        private void ProcessPings()
        {
            int repTime = 0;
            int high = 0;
            int low = 1000000000;
            int timeout = 0;

            foreach (PingReply pr in this.Reply)
            {

                string time;

                if (pr.Status == IPStatus.Success)
                {
                    time = pr.RoundtripTime.ToString() + " ms"; ;
                    this.Buff = pr.Buffer.Length.ToString();
                    this.Ttl = pr.Options.Ttl.ToString();
                    this.IP = pr.Address.ToString();

                    if ((int)pr.RoundtripTime > high)
                        high = (int)pr.RoundtripTime;

                    else if ((int)pr.RoundtripTime < low)
                        low = (int)pr.RoundtripTime;
                }

                else
                {
                    time = "Timeout";
                    timeout++;
                }

                repTime += (int)pr.RoundtripTime;

                string s = String.Format("IP: {0}\tByte: {1}\tResponce time: {2}\t TTL: {3}",
                            this.IP, this.Buff, time, this.Ttl);

                this.PingResult.Add(s);
            }

            double avg = repTime / this.Reply.Count;

            string info = String.Format("Plogger ping results{6}Performed at: {0}{6}Lowest: {1}ms\tHighest: {2}ms\tAverage: {3}ms{6}Number of requests: {4}{6}Number of timeouts: {5}{6}{6}",
                            this.Time.ToString(), low.ToString(), high.ToString(), avg.ToString(), this.Reply.Count, timeout.ToString(), Environment.NewLine);

            this.PingResult.Insert(0, info);
        }

        private void Init(IntPtr pointer)
        {
            this.PingSender = new Ping();
            this.handle = pointer;
        }

        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disp)
        {
            if (!this.disposed)
            {
                if (disp)
                {
                    this.component.Dispose();
                }

                CloseHandle(handle);

                this.PingSender.Dispose();

                this.handle = IntPtr.Zero;

                this.disposed = true;
            }
        }

        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        ~Pinger() {
            Dispose(false);
        }
    }
}
